#ifndef CORE_NETWORKCONNECTION_H
#define CORE_NETWORKCONNECTION_H

class CNetwork;
class CNetConnection;
class CNetAcceptor;
class CNetClient;
class CNetConnector;

enum E_CONNECTION_TYPE
{
	CONN_BASE,
	CONN_ACCEPTOR,
	CONN_CLIENT,
	CONN_CONNECTOR
};

class CNetConnection
{
public:

	CNetConnection();

	virtual ~CNetConnection();

	virtual E_CONNECTION_TYPE getType() const = 0;

	SOCKET getSocket() const;

	s32 getPort() const;

	bool isFree() const;

	void free();

	bool isNew() const;

	bool isConnected() const;

	void close();

protected:

	friend class CNetwork;

	bool m_free;

	bool m_connected;

	SOCKET m_socket;

	s32 m_port;

};


class CNetAcceptor : public CNetConnection
{
public:

	CNetAcceptor();

	~CNetAcceptor();

	E_CONNECTION_TYPE getType() const
	{
		return CONN_ACCEPTOR;
	}

	bool bind(s32 _port);

	bool isNew() const;

	u32 getNumberOfNewClients() const;

	CNetClient *getNewClient(u32 _num);

	CNetClient *popClient();

private:

	friend class CNetwork;

	CArray<CNetClient*> m_newClients;

};


class CNetClient : public CNetConnection
{
public:

	CNetClient();

	~CNetClient();

	E_CONNECTION_TYPE getType() const
	{
		return CONN_CLIENT;
	}

	const char *getIp() const;

	bool send(const CByteArray &_bytes);

	bool send(const Byte *_bytes, u32 _count);

	bool receive();

	bool isNew() const;

	CByteArray &incoming();

	const CByteArray &incoming() const;

protected:

	friend class CNetwork;

	stringc m_ip;

	CByteArray m_incoming;

};


class CNetConnector : public CNetClient
{
public:

	CNetConnector();

	~CNetConnector();

	E_CONNECTION_TYPE getType() const
	{
		return CONN_CONNECTOR;
	}

	bool connect(const char *_host, s32 _port, u32 _retries = 0);

private:

	friend class CNetwork;

};

#endif //CORE_NETWORKCONNECTION_H